package com.stary.pay.wxpay.api.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.stary.pay.wxpay.api.WxpayApiException;
import com.stary.pay.wxpay.api.WxpayConstants;

/**
 * <p>加密工具类</p>
 * @author stary {@link stary1993@qq.com}
 * @since 2019-5-11
 */
public class WxpayEncrypt {

	/**
	 * AES加密
	 * @param data 待处理数据
	 * @param key 秘钥
	 * @return AES加密结果
	 * @throws WxpayApiException
	 */
	public static String aesEncrypt(String data, String key)throws WxpayApiException {
		Security.addProvider(new BouncyCastleProvider());
		try {
			Cipher cipher = Cipher.getInstance(WxpayConstants.ALGORITHM_AES_MODE_PADDING, "BC");
			SecretKeySpec secretKey =new SecretKeySpec(MD5(key).toLowerCase().getBytes(), WxpayConstants.ENCRYPT_TYPE_AES);
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			return base64Encrypt(cipher.doFinal(data.getBytes()));
		} catch (Exception e) {
			throw new WxpayApiException("AES encrypt fail：AES data = " + data , e);
		}
	}

	/**
	 * AES解密
	 * @param data 待处理数据
	 * @param key 秘钥
	 * @return AES解密结果
	 * @throws WxpayApiException
	 */
	public static String aesDecrypt(String data, String key)throws WxpayApiException {
		Security.addProvider(new BouncyCastleProvider());
		try {
			Cipher cipher = Cipher.getInstance(WxpayConstants.ALGORITHM_AES_MODE_PADDING, "BC");
			SecretKeySpec secretKey =new SecretKeySpec(MD5(key).toLowerCase().getBytes(), WxpayConstants.ENCRYPT_TYPE_AES);
			cipher.init(Cipher.DECRYPT_MODE , secretKey);
			return new String(cipher.doFinal(base64Decrypt(data)));
		} catch (Exception e) {
			throw new WxpayApiException("AES decrypt fail:AES data = " + data , e);
		}
	}

	/**
	 * base64加密
	 * @param data 待处理数据
	 * @return base64加密结果
	 * @throws UnsupportedEncodingException
	 */
	public static String base64Encrypt(byte[] data) throws UnsupportedEncodingException {
		return new String(Base64.encodeBase64(data), WxpayConstants.CHARSET_UTF8);
	}
	/**
	 * base64加密
	 * @param data 待处理数据
	 * @return base64加密结果
	 * @throws UnsupportedEncodingException
	 */
	public static String base64EncryptString(String data) throws UnsupportedEncodingException {
		return new String(Base64.encodeBase64(data.getBytes()), WxpayConstants.CHARSET_UTF8);
	}
	/**
	 * base64解密
	 * @param data 待处理数据
	 * @return base64解密结果
	 */
	public static byte[] base64Decrypt(String data) {
		return Base64.decodeBase64(data);
	}

	/**
	 * base64解密
	 * @param data 待处理数据
	 * @return base64解密结果
	 * @throws UnsupportedEncodingException
	 */
	public static String base64DecryptString(String data) throws UnsupportedEncodingException {
		return new String(Base64.decodeBase64(data), WxpayConstants.CHARSET_UTF8);
	}

	/**
	 * 生成 MD5
	 * @param data 待处理数据
	 * @return MD5结果
	 */
	public static String MD5(String data) throws Exception {
		MessageDigest md = MessageDigest.getInstance(WxpayConstants.ENCRYPT_TYPE_MD5);
		byte[] array = md.digest(data.getBytes(WxpayConstants.CHARSET_UTF8));
		StringBuilder sb = new StringBuilder();
		for (byte item : array) {
			sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
		}
		return sb.toString().toUpperCase();
	}

	/**
	 * 生成 HMACSHA256
	 * @param data 待处理数据
	 * @param key 密钥
	 * @return 加密结果
	 * @throws Exception
	 */
	public static String HMACSHA256(String data, String key) throws Exception {
		Mac sha256_HMAC = Mac.getInstance(WxpayConstants.ENCRYPT_TYPE_HMACSHA256);
		SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(WxpayConstants.CHARSET_UTF8), WxpayConstants.ENCRYPT_TYPE_HMACSHA256);
		sha256_HMAC.init(secret_key);
		byte[] array = sha256_HMAC.doFinal(data.getBytes(WxpayConstants.CHARSET_UTF8));
		StringBuilder sb = new StringBuilder();
		for (byte item : array) {
			sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
		}
		return sb.toString().toUpperCase();
	}

}
